﻿using Anley.DomainDrivenDesign.Contract.Application;
using Anley.DomainDrivenDesign.Contract.Configuration;
using Anley.DomainDrivenDesign.Contract.Enums;
using Anley.DomainDrivenDesign.Contract.Extension;

namespace Anley.DomainDrivenDesign.Contract.Authorization;

/// <summary>
/// 授权中间件
/// </summary>
public class AuthorizationMiddleware
{
    private readonly RequestDelegate _next;
    private readonly AuthorizationConfiguration _authorizationConfig;

    /// <summary>
    /// 构造函数
    /// </summary>
    public AuthorizationMiddleware(
        RequestDelegate next,
        IOptionsMonitor<AuthorizationConfiguration> authorizationConfig)
    {
        _next = next;
        _authorizationConfig = authorizationConfig.CurrentValue;
    }

    // 调用
    public async Task InvokeAsync(
        HttpContext context,
        ICurrentUser currentUser)
    {
        // 是否匿名路径
        var allowAnonymous = AllowAnonymous(context);
        if (allowAnonymous)
        {
            await _next(context);
            return;
        }
        // 验证Token
        var jwtToken = context.Request.Headers[AneConsts.JwtTokenHeaderName].FirstOrDefault();
        if (string.IsNullOrWhiteSpace(jwtToken))
        {
            UnauthorizedRequest(context);
            return;
        }
        if (jwtToken.StartsWith("Bearer "))
            jwtToken = jwtToken.Replace("Bearer ", "");
        if (!AuthorizationHelper.VerifyAccessToken(jwtToken!, out ICurrentUser? tokenUser))
        {
            UnauthorizedRequest(context);
            return;
        }
        if (tokenUser == null)
        {
            UnauthorizedRequest(context);
            return;
        }
        // 注入当前用户信息
        tokenUser.CopyTo(currentUser);
        // 继续执行
        await _next(context);
    }

    /// <summary>
    /// 允许匿名
    /// </summary>
    /// <param name="httpContext"></param>
    private bool AllowAnonymous(
        HttpContext httpContext)
    {
        // 判断是否允许匿名
        var endpoint = httpContext.GetEndpoint();
        if (!(endpoint is null))
        {
            var allowAnonymous = endpoint.Metadata.GetMetadata<IAllowAnonymous>();
            if (!(allowAnonymous is null))
                return true;
        }
        // 判断是否白名单
        var requestPath = httpContext.Request.Path.Value;
        if (!string.IsNullOrWhiteSpace(requestPath))
            if (!(_authorizationConfig == null) && !(_authorizationConfig.AnonymousPaths == null) && _authorizationConfig.AnonymousPaths.Count > 0)
                foreach (var path in _authorizationConfig.AnonymousPaths)
                    if (requestPath.StartsWith(path))
                    {
                        return true;
                    }
        // 未命中
        return false;
    }

    /// <summary>
    /// 未授权请求
    /// </summary>
    /// <param name="context"></param>
    private async void UnauthorizedRequest(
        HttpContext context)
    {
        var aneResult = new AneResult(AneResultCode.Unauthorized);
        var jsonStr = JsonConvert.SerializeObject(aneResult, Formatting.Indented, new JsonSerializerSettings()
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver(),
            NullValueHandling = NullValueHandling.Ignore
        });
        context.Response.ContentType = AneConsts.JSONContentType;
        await context.Response.WriteAsync(jsonStr, Encoding.UTF8).ConfigureAwait(false);
    }
}